package drds.plus.parser;

import drds.plus.parser.abstract_syntax_tree.statement.Statement;
import drds.plus.parser.lexer.Lexer;
import drds.plus.parser.lexer.Token;
import drds.plus.parser.parser.ExpressionParser;
import drds.plus.parser.parser.SelectParser;
import drds.plus.parser.parser.dml.DeleteParser;
import drds.plus.parser.parser.dml.UpdateParser;
import drds.plus.parser.parser.dml.add.InsertParser;
import drds.plus.parser.parser.dml.add.ReplaceParser;


public final class SqlParser {


    private static String buildErrorMsg(Exception e, Lexer lexer, String sql) {
        StringBuilder sb = new StringBuilder("You have an error in your SQL parser; Error occurs around this fragment: ");
        final int ch = lexer.getCurrentIndex();
        int from = ch - 16;
        if (from < 0)
            from = 0;
        int to = ch + 9;
        if (to >= sql.length())
            to = sql.length() - 1;
        String fragment = sql.substring(from, to + 1);
        sb.append('{').append(fragment).append('}');
        if (e != null) {
            sb.append(". Error cause: " + e.getMessage());
        }
        return sb.toString();
    }

    public static Statement parse(String sql, Lexer lexer) {
        try {
            Statement statement = null;
            boolean isEOF = true;
            ExpressionParser expressionParser = new ExpressionParser(lexer);
            stmtSwitch:
            switch (lexer.token()) {


                case KW_INSERT:
                    statement = new InsertParser(lexer, expressionParser).insert();
                    break stmtSwitch;
                case KW_REPLACE:
                    statement = new ReplaceParser(lexer, expressionParser).replace();
                    break stmtSwitch;
                case KW_UPDATE:
                    statement = new UpdateParser(lexer, expressionParser).update();
                    break stmtSwitch;
                case KW_DELETE:
                    statement = new DeleteParser(lexer, expressionParser).delete();
                    break stmtSwitch;
                case KW_SELECT:
                case PUNC_LEFT_PAREN:
                    statement = new SelectParser(lexer, expressionParser).union();
                    break stmtSwitch;
                default:
                    throw new RuntimeException("chars is not a supported statement");
            }
            if (isEOF) {
                while (lexer.token() == Token.PUNC_SEMICOLON) {
                    lexer.nextToken();
                }

                if (lexer.token() != Token.end_of_sql) {
                    throw new RuntimeException(buildErrorMsg(null, lexer, sql));
                }
            }
            return statement;
        } catch (Exception e) {
            throw new RuntimeException(buildErrorMsg(e, lexer, sql), e);
        }
    }

    public static Statement parse(String sql) throws RuntimeException {
        return parse(sql, new Lexer(sql));
    }


}
